package com.senlingspace.system.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Maps;
import com.senlingspace.common.core.domain.AjaxResult;
import com.senlingspace.common.core.redis.RedisCache;
import com.senlingspace.common.request.WxLoginCodeRequest;
import com.senlingspace.common.utils.JwtUtilExt;
import com.senlingspace.common.utils.StringUtils;
import com.senlingspace.system.domain.SlkjCustomer;
import com.senlingspace.system.service.ISlkjCustomerService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * 小程序登录服务实现类
 *
 * @author lebronjames
 * @date 2024/10/21
 */
@Service
@AllArgsConstructor
@Slf4j
public class MiniAppAuthService {

    private final RedisCache redisCache;
    private final WxMaService wxMaService;
    private final ISlkjCustomerService iSlkjCustomerService;

    private final static String CUSTOMER_LOGIN_KEY = "wmp_customer_login:";

    /**
     * 微信小程序登录逻辑
     */
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult login(WxLoginCodeRequest request) {
        String openId = getUserOpenId(request);
        if (openId == null) {
            return AjaxResult.error("登录失败！");
        }

        String phoneNumber = getUserPhoneNumber(request);
        if (phoneNumber == null) {
            return AjaxResult.error("手机号获取失败！");
        }

        SlkjCustomer customer = iSlkjCustomerService.getCustomerByPhoneExt(phoneNumber, openId);
        String key = CUSTOMER_LOGIN_KEY + phoneNumber;
        String token = buildUserToken(customer.getCustomerId(), customer.getNickname(), customer.getPhone());

        redisCache.setCacheObject(key, token, JwtUtilExt.EXPIRE_DAY * 24 * 60 * 60, TimeUnit.SECONDS);
        WxMaConfigHolder.remove();
        log.info("微信小程序，用户 [{}] 登录成功！！！", customer.getPhone());

        JSONObject data = new JSONObject();
        data.put("token", token);
        data.put("phone", customer.getPhone());
        data.put("openId", customer.getOpenId());
        return AjaxResult.success("success", data);
    }

    /**
     * 退出登录逻辑
     */
    public AjaxResult logout(String mobile) {
        log.info("微信小程序 [{}] 退出登录", mobile);
        String key = CUSTOMER_LOGIN_KEY + mobile;
        redisCache.deleteObject(key);
        return AjaxResult.success("success");
    }

    private String getUserPhoneNumber(WxLoginCodeRequest request) {
        try {
            WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(request.getCode());
            if (StringUtils.isBlank(phoneNoInfo.getPhoneNumber())) {
                log.error("手机号为空！");
                return null;
            }
            return phoneNoInfo.getPhoneNumber();
        } catch (WxErrorException e) {
            log.error("用户手机号获取失败！", e);
            return null;
        }
    }

    private String getUserOpenId(WxLoginCodeRequest request) {
        try {
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(request.getJsCode());
            if (StringUtils.isBlank(sessionInfo.getOpenid())) {
                log.error("openid 为空！");
                return null;
            }
            return sessionInfo.getOpenid();
        } catch (WxErrorException e) {
            log.error("用户 openid 获取失败！", e);
            return null;
        }
    }

    private static String buildUserToken(Long customerId, String nickname, String phone) {
        HashMap<String, Object> payload = Maps.newHashMap();
        long expire = System.currentTimeMillis() + 1000 * 60 * 60 * 24 * JwtUtilExt.EXPIRE_DAY;
        payload.put("customer_id", customerId);
        payload.put("nickname", nickname);
        payload.put("phone", phone);
        return JwtUtilExt.createToken(payload, expire);
    }

}
